#include "Precompilador.h"

char* Precompilador::buscarReemplazos(char* linea,	ContenedorDeDefines* lista) {
	int k = 0;
	char segundaMitadLinea[LONGITUD_LINEA_LEIDA];
	int longNombreDelDefine;
	int longValorDelDefine;
	char* siguienteMatch = NULL;
	char* punteroIteradorDeLinea = NULL;
	char* caracterAnteriorAlMatch = NULL;
	char* caracterPosteriorAlMatch = NULL;
	char* ptrSegundaMitadLinea = &segundaMitadLinea[0];
	char lineaAux[LONGITUD_LINEA_LEIDA];
	char* defineActual = NULL;
	char* valorDefineActual = NULL;
	strcpy(lineaAux, linea);

	//  un ciclo por define
	for (k = 0; k <= lista->indexMatrizDefines; k++) {
		defineActual = lista->getDefine(k);
		valorDefineActual = lista->getValorDefine(k);
		longNombreDelDefine = strlen(defineActual);
		longValorDelDefine = strlen(valorDefineActual);
		siguienteMatch = strstr(lineaAux, defineActual);

		//  busco coincidencias
		while (siguienteMatch != NULL) {
			caracterAnteriorAlMatch = (char*)(siguienteMatch - 1);
			caracterPosteriorAlMatch = (char*)(siguienteMatch+ longNombreDelDefine);

			if (siguienteMatch == lineaAux)
				*caracterAnteriorAlMatch = '/';
			//  match en 1era letra de linea->lo seteo a un separador valido

			/* con esto valido que la ocurrencia no sea parte de
			 * una palabra distinta. Ejemplo api, pi.
			 */
			if (sepValidos.esSeparadorValido(*caracterAnteriorAlMatch) == TRUE
					&& sepValidos.esSeparadorValido(*caracterPosteriorAlMatch) == TRUE) {
				punteroIteradorDeLinea = siguienteMatch + longNombreDelDefine;

				/*1-copio lo que va despues de la coincidencia
				 *2-reemplazo
				 *3-restauro lo que habia despues de la coincidencia
				 *4-reposiciono el puntero luego del reemplazo
				 **/

				/* 01234567890123456
				 * float t = pi*2;
				 *
				 * Se hace una copia de *2;
				 * reemplazo pi por su valor
				 * ,entonces queda: float t = 3.14159"·$%T...
				 * (luego del reemplazo probablemente haya basura)
				 * y finalmente concateno con la 1er copia que habia hecho, no sin antes apuntar
				 * a la posicion correcta...
				 *
				 * */
				strcpy(ptrSegundaMitadLinea, punteroIteradorDeLinea);
				strcpy(siguienteMatch, valorDefineActual);
				punteroIteradorDeLinea = siguienteMatch + longValorDelDefine;
				//  uno ambas "mitades"
				strcat(punteroIteradorDeLinea, ptrSegundaMitadLinea);
			} else {
				/* si la linea contiene api, y yo tengo un define "pi"
				 * de no posicionar el puntero delante de la ocurrencia
				 * voy a quedar en un loop infinito, siempre hallando
				 * la misma coincidencia
				 * */
				punteroIteradorDeLinea = siguienteMatch + 1;
			}
			siguienteMatch = strstr(punteroIteradorDeLinea, lista->getDefine(k));
		}  //  fin ciclo while
	}  //  fin ciclo for
	strcpy(linea, lineaAux);

	return linea;
}

char* Precompilador::quitarComentarios(char* linea, FlagsDePrograma* flags) {
	char lineaAux[LONGITUD_LINEA_LEIDA] = {0};

	flags->comentarioAbiertoEnLineaActual = FALSE;

	if (flags->comentarioAbierto == FALSE) {
		buscarAperturaDeComentarioOBarraDoble(lineaAux, linea, flags);
	}
	/*
	 * no seria adecuado poner un else if(flags->comentarioAbierto == TRUE)
	 * porque flags->comentarioAbierto puede cambiar su valor
	 * dentro de buscarAperturaDeComentarioOBarraDoble,
	 * ya que, justamente, su tarea es buscar apertura de comentarios.
	 */
	if (flags->comentarioAbierto == TRUE) {
		buscarCierreDeComentario(lineaAux, linea, flags);
	}

	strcpy(linea, lineaAux);
	return linea;
}

void Precompilador::buscarAperturaDeComentarioOBarraDoble(char* lineaAux,
		char* linea, FlagsDePrograma* flags) {
	char* ptrIteradorLinea = linea;
	char* siguienteMatch = strstr(ptrIteradorLinea, BARRASDOBLES);

	if (siguienteMatch != NULL) {
		strncpy(lineaAux, linea, siguienteMatch - linea);
		lineaAux[siguienteMatch - linea] = BARRA_N;
		flags->todaviaTieneComentarios = FALSE;
	}
	else {
		siguienteMatch = strstr(ptrIteradorLinea, APERTURA_COMENTARIO);

		if (siguienteMatch != NULL) {
			flags->comentarioAbierto = TRUE;
			strncpy(lineaAux, linea, siguienteMatch - linea);
			lineaAux[siguienteMatch - linea] = (int) NULL;
			ptrIteradorLinea = siguienteMatch;
			flags->comentarioAbiertoEnLineaActual = TRUE;
		}
		else {
			strcpy(lineaAux, linea);
			flags->todaviaTieneComentarios = FALSE;
		}
	}
}

void Precompilador::buscarCierreDeComentario(char* lineaAux, char* linea,
		FlagsDePrograma* flags) {
	char* ptrIteradorLinea = linea;
	char* siguienteMatch = strstr(ptrIteradorLinea, CIERRE_COMENTARIO);

	if (siguienteMatch != NULL) {
		flags->comentarioAbierto = FALSE;

		/*  Si hubo una apertura de comentario en la linea actual,
		 *  lo que no estaba comentado esta en lineaAux.
		 *  siguienteMatch+2 apunta al 1er carac no comentado luego del cierre de comentario
		 *  Entonces, concateno ambas partes*/
		if (flags->comentarioAbiertoEnLineaActual == TRUE) {
			strcat(lineaAux, siguienteMatch + 2);
		} else {
			/* El flujo del programa llego a este punto porque
			 * se hallo un cierre de comentario, pero la apertura
			 * se realizo en una linea anterior.
			 * No puedo concatenar, porque lineaAux tiene basura
			 * */
			strcpy(lineaAux, siguienteMatch + 2);
		}
	} else {
		flags->todaviaTieneComentarios = FALSE;
	}
}
